/**
 * 剑指 Offer 67. 把字符串转换成整数
 * https://leetcode-cn.com/problems/ba-zi-fu-chuan-zhuan-huan-cheng-zheng-shu-lcof/
 */

const digitsMap = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

/**
 * @param {string} str
 * @param {number} index
 * @return {boolean}
 */
function isIndexNumber(str, index) {
  const char = str[index];
  return char >= '0' && char <= '9';
}

/**
 * @param {string} str
 * @return {number}
 */
function strToInt(str) {
  let firstValidIndex = -1;
  for (let i = 0; i < str.length; i += 1) {
    const char = str[i];
    if (char !== ' ') {
      if (
        char === '+' || char === '-'
        || isIndexNumber(str, i)
      ) {
        firstValidIndex = i;
      }
      break;
    }
  }
  if (firstValidIndex < 0) {
    return 0;
  }
  let isPositive = true;
  let numberBegin;
  const firstChar = str[firstValidIndex];
  if (firstChar === '+' || firstChar === '-') {
    if (firstChar === '-') {
      isPositive = false;
    }
    numberBegin = firstValidIndex + 1;
  } else {
    numberBegin = firstValidIndex;
  }
  if (!isIndexNumber(str, numberBegin)) {
    return 0;
  }
  while (numberBegin < str.length && str[numberBegin] === '0') {
    numberBegin += 1;
  }
  if (numberBegin >= str.length || !isIndexNumber(str, numberBegin)) {
    return 0;
  }
  let numberEnd = numberBegin + 1;
  while (numberEnd < str.length && isIndexNumber(str, numberEnd)) {
    numberEnd += 1;
  }
  const length = numberEnd - numberBegin;
  if (length > 10) {
    return isPositive ? 2147483647 : -2147483648;
  }
  if (length === 10) {
    const max = '2147483648';
    let isEqual = true;
    for (let i = numberBegin; i < numberEnd; i += 1) {
      const char1 = str[i];
      const char2 = max[i - numberBegin];
      if (char1 > char2) {
        return isPositive ? 2147483647 : -2147483648;
      }
      if (char1 < char2) {
        isEqual = false;
        break;
      }
    }
    if (isEqual) {
      return isPositive ? 2147483647 : -2147483648;
    }
  }
  let number = 0;
  for (let i = numberBegin; i < numberEnd; i += 1) {
    number *= 10;
    number += digitsMap[str[i]];
  }
  return isPositive ? number : -number;
}

console.log(strToInt('42') === 42);
console.log(strToInt('   -42') === -42);
console.log(strToInt('4193 with words') === 4193);
console.log(strToInt('words and 987') === 0);
console.log(strToInt('-91283472332') === -2147483648);
console.log(strToInt('  0000000000012345678') === 12345678);
console.log(strToInt('    0000000000000   ') === 0);
console.log(strToInt('2147483648') === 2147483647);
